package org.terukusu.util;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 初期容量を上限とするLRUキャッシュ。
 * 要素を取り出すたびに要素の入れ替えが発生するので注意。
 *
 * @author Teruhiko Kusunoki&lt;<a href="teru.kusu@gmail.com">teru.kusu@gmail.com</a>&gt;
 *
 */
public class LRULinkedHashMap<K, V> extends LinkedHashMap<K , V>{

    /**
     * LRULinkedHashMap.java
     */
    private static final long serialVersionUID = -1672175483624184554L;

    private final int initialCapacity;

    /**
     * 新しいオブジェクトを生成します。
     *
     */
    public LRULinkedHashMap() {
        super();
        initialCapacity = 0;
   }

    /**
     * 新しいオブジェクトを生成します。
     *
     * @param initialCapacity
     * @param loadFactor
     * @param accessOrder
     */
    public LRULinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
        super(initialCapacity, loadFactor, accessOrder);
        this.initialCapacity = initialCapacity;
    }

    /**
     * 新しいオブジェクトを生成します。
     *
     * @param initialCapacity
     * @param loadFactor
     */
    public LRULinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        this.initialCapacity = initialCapacity;
    }

    /**
     * 新しいオブジェクトを生成します。
     *
     * @param initialCapacity
     */
    public LRULinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        this.initialCapacity = initialCapacity;
    }

    /**
     * 新しいオブジェクトを生成します。
     *
     * @param m
     */
    public LRULinkedHashMap(Map<? extends K, ? extends V> m) {
        super(m);
        initialCapacity = 0;
    }

    /*
     * (non-Javadoc)
     * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry)
     */
    @Override
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest)  {
        if (initialCapacity > 0) {
            return size() > initialCapacity;
        } else {
            return super.removeEldestEntry(eldest);
        }
    }

    /* (non-Javadoc)
     * @see java.util.LinkedHashMap#get(java.lang.Object)
     */
    @Override
    @SuppressWarnings("unchecked")
    public V get( Object key ) {
        V value = super.get( key );
        if ( value != null ) {
            remove( key );
            put( (K) key, value );
        }
        return value;
    }
}
